#include "thread_impl_win32.h"


namespace sys{
	DWORD __stdcall thread_proc(LPVOID);

	thread* create_thread(kcwstr _name, thread_route* _route, kbyte _attrib, dword _stack_size)
	{
		win32_thread* thread = new win32_thread(_name);

		if (thread->create(_route, _attrib, _stack_size))
			return thread;

		thread->release();
		return nullptr;
	}

	win32_thread::win32_thread(kcwstr _name)
	{
		m_name = _name;
	}

	bool win32_thread::create(thread_route* _route, kbyte _attrib, dword _stack_size)
	{
		m_attrib		= _attrib;
		m_stack_size	= _stack_size;
		m_proute		= _route;

		bool auto_start = (_attrib & thread::autostart) != 0;

		HANDLE handle = ::CreateThread(nullptr
			, (dword)_stack_size
			, thread_proc
			, this
			, auto_start ? CREATE_SUSPENDED : 0
			, NULL);

		if (handle == 0)
		{
			return false;
		}

		m_hthread = handle;

		m_hevent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
		::ResetEvent(m_hevent);
		
		return true;
	}		

	bool win32_thread::start()
	{
		if ( !(m_attrib & thread::autostart) || is_paused() )
		{
			if (-1 != ::ResumeThread(m_hthread))
			{
				m_is_paused = false;
			}
		}
		return false;
	}

	bool win32_thread::pause()
	{
		if ( running() )
		{
			
			if (-1 != ::SuspendThread(m_hthread))
			{
				m_is_paused = true;
			}
		}
		return false;
	}

	bool win32_thread::terminal(dword _exit_code)
	{
		if (!running())
			return false;

		::TerminateThread(m_hthread, _exit_code);

		::CloseHandle(m_hevent);
		m_hevent = 0;

		::CloseHandle(m_hthread);
		m_hthread = 0;

		return true;

	}

	bool win32_thread::join(dword _mesc)
	{
		if (!running())
		{
			return false;
		}

		if (_mesc == 0)
			_mesc = INFINITE;

		bool result = false;
		int rst = ::WaitForSingleObject(m_hthread, _mesc);

		if (rst == WAIT_OBJECT_0 || rst == WAIT_ABANDONED)
		{
			CloseHandle(m_hevent);
			CloseHandle(m_hthread);
			m_hthread = 0;

			return true;
		}

		return false;
	}

	win32_thread::~win32_thread()
	{
		if (running())
		{
			terminal(0);
		}
		cmn::safe_release(m_proute);
	}

	dword win32_thread::release()
	{
		delete this;
		return 0;
	}

	DWORD __stdcall thread_proc(LPVOID _param)
	{
		sys::win32_thread* pthread = (sys::win32_thread*)_param;

		TlsSetValue(sys::win32_thread::TLS_INDEX_THREAD, pthread->m_hthread);
		HANDLE ev = pthread->m_hevent;

		pthread->m_proute->main();

		return 0;
	}
}



